package com.kingmed.kmss.admin.modules.sys.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.kingmed.kmss.admin.modules.sys.mapper.SysDataDictMapper;
import com.kingmed.kmss.admin.modules.sys.model.SysDataDict;
import com.kingmed.kmss.admin.modules.sys.service.SysDataDictService;
import com.kingmed.kmss.common.constant.sys.CacheConstants;
import com.kingmed.kmss.common.service.sys.RedisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 系统数据字典表 服务实现类
 * </p>
 *
 * @author WYL
 * @since 2022-12-14
 */
@Service
public class SysDataDictServiceImpl extends ServiceImpl<SysDataDictMapper, SysDataDict> implements SysDataDictService {

    @Autowired
    private RedisService redisService;
    @Value("${redis.expire.common}")
    private Long REDIS_EXPIRE;

    @Transactional
    @Override
    public int create(List<SysDataDict> dataDictList) {
        this.saveBatch(dataDictList);
        this.updateRedisDict(dataDictList);
        return dataDictList.size();
    }

    @Transactional
    @Override
    public int update(List<SysDataDict> dataDictList) {
        this.saveOrUpdateBatch(dataDictList);
        this.updateRedisDict(dataDictList);
        return dataDictList.size();
    }

    @Transactional
    @Override
    public int delete(List<Long> dataDictIdList) {
        List<SysDataDict> dataDictList = this.getBaseMapper().selectBatchIds(dataDictIdList);
        this.getBaseMapper().deleteBatchIds(dataDictIdList);
        this.updateRedisDict(dataDictList);
        return dataDictIdList.size();
    }

    @Override
    public void deleteByCode(String dictCode) {
        this.getBaseMapper().delete(new QueryWrapper<SysDataDict>().lambda().eq(SysDataDict::getDictCode, dictCode));
    }

    @Override
    public Page<SysDataDict> list(String dictNameKey, String dictValueKey, Integer pageSize, Integer pageNum) {
        Page<SysDataDict> pageDict = new Page<>(pageNum, pageSize);

        QueryWrapper<SysDataDict> wrapper = new QueryWrapper<>();
        LambdaQueryWrapper<SysDataDict> lambdaWrapper = wrapper.lambda();
        if (StrUtil.isNotEmpty(dictNameKey)) {
            lambdaWrapper.and(Wrapper -> Wrapper.like(SysDataDict::getDictCode, dictNameKey).or().like(SysDataDict::getDictName, dictNameKey));
        }
        if (StrUtil.isNotEmpty(dictValueKey)) {
            lambdaWrapper.and(Wrapper -> Wrapper.like(SysDataDict::getDictKey, dictValueKey).or().like(SysDataDict::getDictValue, dictValueKey));
        }
        return page(pageDict, wrapper);
    }

    @Override
    public Page<SysDataDict> listCodes(String dictNameKey, Integer pageSize, Integer pageNum) {
        Page<SysDataDict> pageDict = new Page<>(pageNum, pageSize);
        return this.getBaseMapper().listCodes(pageDict, dictNameKey);
    }

    /**
     * 精准查询
     */
    @Override
    public List<SysDataDict> query(SysDataDict sysDataDict) {
        LambdaQueryWrapper<SysDataDict> queryWrapper = new QueryWrapper<SysDataDict>().lambda()
                .eq(StrUtil.isNotEmpty(sysDataDict.getDictName()), SysDataDict::getDictName, sysDataDict.getDictName())
                .eq(StrUtil.isNotEmpty(sysDataDict.getDictKey()), SysDataDict::getDictKey, sysDataDict.getDictKey())
                .eq(StrUtil.isNotEmpty(sysDataDict.getDictCode()), SysDataDict::getDictCode, sysDataDict.getDictCode())
                .eq(StrUtil.isNotEmpty(sysDataDict.getDictValue()), SysDataDict::getDictValue, sysDataDict.getDictValue());
        return this.list(queryWrapper);
    }

    /**
     * 根据数据字典code查询
     */
    @Override
    public List<SysDataDict> queryByCode(String dictCode) {
        String redisKey = CacheConstants.SYS_DICT_KEY.concat(dictCode);
        // 先从缓存中取
        List<SysDataDict> dataDictList = (List<SysDataDict>) redisService.get(redisKey);
        if (CollectionUtils.isEmpty(dataDictList)) {
            // 查询数据库
            dataDictList = this.list(new QueryWrapper<SysDataDict>().lambda()
                    .eq(SysDataDict::getDictCode, dictCode)
                    .orderByAsc(SysDataDict::getDictSort)
            );
            if (!CollectionUtils.isEmpty(dataDictList)) {
                redisService.set(redisKey, dataDictList, REDIS_EXPIRE);
            }
        }
        return dataDictList;
    }

    /**
     * 根据数据字典code查询
     */
    @Override
    public Map<String, String> queryMapByCode(String dictCode) {
        // 先从缓存中取
        List<SysDataDict> dataDictList = this.queryByCode(dictCode);
        Map<String, String> map = new HashMap<>();
        for (SysDataDict sysDataDict : dataDictList) {
            map.put(sysDataDict.getDictKey(), sysDataDict.getDictValue());
        }
        return map;
    }

    @Override
    public Map<String, List<SysDataDict>> queryByCodeBatch(List<String> dictCodes) {
        Map<String, List<SysDataDict>> resultMap = new HashMap<>();
        for (String dictCode : dictCodes) {
            resultMap.put(dictCode, this.queryByCode(dictCode));
        }
        return resultMap;
    }

    /**
     * 根据数据字典code + key查询
     */
    @Override
    public List<SysDataDict> queryByCodeKey(String dictCode, String dictKey) {
        String redisKey = CacheConstants.SYS_DICT_KEY.concat(dictCode).concat(dictKey);
        // 先从缓存中取
        List<SysDataDict> dataDictList = (List<SysDataDict>) redisService.get(redisKey);
        if (CollectionUtils.isEmpty(dataDictList)) {
            // 查询数据库
            dataDictList = this.list(new QueryWrapper<SysDataDict>().lambda()
                            .eq(SysDataDict::getDictCode, dictCode)
                            .eq(SysDataDict::getDictKey, dictKey)
                            .orderByAsc(SysDataDict::getDictSort)
                    //.orderByAsc(SysDataDict::getDictKey)
            );
            redisService.set(redisKey, dataDictList, REDIS_EXPIRE);
        }
        return dataDictList;
    }

    /**
     * 更新缓存中的字典数据
     */
    private void updateRedisDict(List<SysDataDict> dataDictList) {
        // 批量修改时：防止重复更新
        List<String> updateAlreadyKeys = CollUtil.newArrayList();

        for (SysDataDict dict : dataDictList) {
            String redisKeyByCode = CacheConstants.SYS_DICT_KEY.concat(StrUtil.trim(dict.getDictCode()));
            if (!updateAlreadyKeys.contains(redisKeyByCode)) {
                // 更新缓存 按code
                List<SysDataDict> listByCode = this.list(new QueryWrapper<SysDataDict>().lambda()
                        .eq(SysDataDict::getDictCode, StrUtil.trim(dict.getDictCode()))
                        .orderByAsc(SysDataDict::getDictSort)
                );
                redisService.del(redisKeyByCode);
                if (listByCode != null && !listByCode.isEmpty()) {
                    redisService.set(redisKeyByCode, listByCode, REDIS_EXPIRE);
                }
                updateAlreadyKeys.add(redisKeyByCode);
            }

            String redisKeyByCodeKey = CacheConstants.SYS_DICT_KEY
                    .concat(StrUtil.trim(dict.getDictCode())).concat(StrUtil.trim(dict.getDictKey()));
            if (!updateAlreadyKeys.contains(redisKeyByCodeKey)) {
                // 更新缓存 按code+key
                List<SysDataDict> listByCodeKey = this.list(new QueryWrapper<SysDataDict>().lambda()
                        .eq(SysDataDict::getDictCode, dict.getDictCode())
                        .eq(SysDataDict::getDictKey, dict.getDictKey())
                        .orderByAsc(SysDataDict::getDictSort)
                );
                redisService.del(redisKeyByCodeKey);
                if (listByCodeKey != null && !listByCodeKey.isEmpty()) {
                    redisService.set(redisKeyByCodeKey, listByCodeKey, REDIS_EXPIRE);
                }
                updateAlreadyKeys.add(redisKeyByCodeKey);
            }
        }

    }
}
